using System;
using System.Speech.Synthesis;
using System.Speech.Recognition;
using System.Collections.Generic;
using System.Globalization;
using System.Windows.Forms;
using System.IO;

namespace C4F.DevKit.Speech
{
    [System.ComponentModel.ToolboxItem(true), System.Drawing.ToolboxBitmap(typeof(SapiManager))]
    /// <summary>
    /// Speech API's main class.
    /// </summary>
    public class SapiManager : System.ComponentModel.Component
    {

        #region Globals

        /// <summary>
        /// Global variables required.
        /// </summary>
        private SpeechSynthesizer speechSynthesizer;
        private SpeechRecognitionEngine recognizerEngine;
        private SpeechRecognitionEngine dictationRecognizerEngine;
        private Grammar customGrammar;
        private DictationGrammar dictationGrammar;
        private Prompt currentPrompt;
        private List<VoiceInfo> voices;

        private int DEFAULT_SPEECH_RATE = 2;
        private int DEFAULT_SPEECH_VOLUME = 50;
        private const string WAV_EXTENSION = "wav";
        
        #endregion
        
        #region Methods

        /// <summary>
        /// Constructor for SAPI class.
        /// </summary>
        public SapiManager()
        {
            // Intialize speechSynthesizer object.
            speechSynthesizer = new SpeechSynthesizer();
            speechSynthesizer.StateChanged += new EventHandler<System.Speech.Synthesis.StateChangedEventArgs>(SpeechSynthesizerStateChanged);
            this.StateChanged += new SapiStateChnageEventHandler(SapiManager_StateChanged);
            this.SpeechRecognized += new SapiSpeechRecognizedEventHandler(SapiManager_SpeechRecognized);

            this.speechSynthesizer.Volume = this.DEFAULT_SPEECH_VOLUME;
            this.speechSynthesizer.Rate = this.DEFAULT_SPEECH_RATE;

            try
            {
                voices = this.GetAllInstalledVoices();
            }
            catch
            {
                voices = null;
            }
            
            try
            {
                if (voices.Count > 0 && !string.IsNullOrEmpty(voices[0].Name))
                    this.SelectVoice(voices[0].Name);  // use the first voice by default
            }
            catch
            {
                // Do nothing
            }
        }

        /// <summary>
        /// Returns a list of voices that can be used.
        /// </summary>        
        public List<VoiceInfo> Voices
        {
            get { return voices ?? new List<VoiceInfo>(); }
        }

        /// <summary>
        /// Current voice being used. If you'd like to change the selected voice, use the SelectVoice method.
        /// </summary>
        public VoiceInfo CurrentVoice
        {
            get
            {
                string voiceId = speechSynthesizer.Voice.Id;
                VoiceInfo voiceInfo = new VoiceInfo();

                if (Voices != null)
                {
                    foreach (VoiceInfo voice in Voices)
                    {
                        if (voice.VoiceId == voiceId)
                        {
                            voiceInfo = voice;
                            break;
                        }
                    }
                }

                return voiceInfo;
            }
        }

        /// <summary>
        /// Iternal purpose. 
        /// </summary>
        /// <param name="text"></param>
        void SapiManager_SpeechRecognized(string text)
        {         
        }

        /// <summary>
        /// Iternal purpose.
        /// </summary>
        void SapiManager_StateChanged()
        {        
        }

        #region Events and delegates

        /// <summary>
        /// Custom event handler for speech-recognition event.  
        /// </summary>
        /// <param name="text">Returns speech text recognized.</param>
        public delegate void SapiSpeechRecognizedEventHandler(string text);

        /// <summary>
        /// Event occurs whenever recognition system recognizes speech.
        /// </summary>
        public event SapiSpeechRecognizedEventHandler SpeechRecognized;

        /// <summary>
        /// Custom event handler for speech-state change event.
        /// </summary>
        public delegate void SapiStateChnageEventHandler();

        /// <summary>
        /// Event occurs whenever speech engine's state changes.
        /// </summary>
        public event SapiStateChnageEventHandler StateChanged;

        #endregion

        #region Synthesizer related methods

        private void SpeechSynthesizerStateChanged(object sender, System.Speech.Synthesis.StateChangedEventArgs e)
        {
            StateChanged();
        }
                
        /// <summary>
        /// Lists all the voices installed on the machine.
        /// </summary>
        /// <returns>List of structure of voiceinfo installed on the machine.</returns>
        /// <exception cref="SapiManagerException">Thrown when 
        /// collecting information about voices installed.</exception>
        public List<VoiceInfo> GetAllInstalledVoices()
        {
            try
            {
                List<VoiceInfo> installedVoices = new List<VoiceInfo>();
                System.Collections.ObjectModel.ReadOnlyCollection<InstalledVoice> voices = speechSynthesizer.GetInstalledVoices(CultureInfo.CurrentCulture);
                foreach (InstalledVoice voice in voices)
                {                    
                    installedVoices.Add( ToLocalVoiceInfo(voice) );
                }
                return installedVoices;
            }
            catch (Exception exception)
            {
                throw new SapiManagerException(exception.Message, exception);
            }
        }

        private VoiceInfo ToLocalVoiceInfo(InstalledVoice voice)
        {
            VoiceInfo voiceInfo = new VoiceInfo();
            voiceInfo.Age = (VoiceAge)voice.VoiceInfo.Age;
            voiceInfo.Description = voice.VoiceInfo.Description;
            voiceInfo.Gender = (VoiceGender)voice.VoiceInfo.Gender;
            voiceInfo.VoiceId = voice.VoiceInfo.Id;
            voiceInfo.Name = voice.VoiceInfo.Name;

            return voiceInfo;
        }
                
        /// <summary>
        /// Voice rate.
        /// </summary>        
        public int VoiceRate
        {

            get { return speechSynthesizer.Rate; }

            set { speechSynthesizer.Rate = value; }

        }

        /// <summary>
        /// Voice volume.
        /// </summary>
        public int VoiceVolume
        {

            get { return speechSynthesizer.Volume; }

            set { speechSynthesizer.Volume = value; }

        }

        /// <summary>
        /// Sapi state.
        /// </summary>
        public SynthesizerState State
        {

            get { return (SynthesizerState)speechSynthesizer.State; }

        }

        /// <summary>
        /// Sets the voice for speaking.
        /// </summary>
        /// <param name="personName">Voice name to set.</param>
        /// <exception cref="SapiManagerException">Thrown when 
        /// setting voice to read fails.</exception>
        public void SelectVoice(string personName)
        {
            try
            {
                speechSynthesizer.SelectVoice(personName);
            }

            catch (Exception exception)
            {
                throw new SapiManagerException(exception.Message, exception);
            }

        }

        /// <summary>
        /// Sets the voice for speaking.
        /// </summary>
        /// <param name="personGender">Gender name to setting voice.</param>
        /// <exception cref="SapiManagerException">Thrown when 
        /// setting voice to read fails.</exception>
        public void SelectVoice(VoiceGender personGender)
        {

            try
            {
                speechSynthesizer.SelectVoiceByHints((System.Speech.Synthesis.VoiceGender)personGender);
            }

            catch (Exception exception)
            {
                throw new SapiManagerException(exception.Message, exception);
            }

        }
        
        /// <summary>
        /// Sets the voice for speaking.
        /// </summary>
        /// <param name="personGender">Gender of voice.</param>
        /// <param name="personAge">Age of voice</param>
        /// <exception cref="SapiManagerException">Thrown when 
        /// setting voice to read fails.</exception>
        public void SelectVoice(VoiceGender personGender, VoiceAge personAge)
        {
            try
            {
                speechSynthesizer.SelectVoiceByHints((System.Speech.Synthesis.VoiceGender)personGender, (System.Speech.Synthesis.VoiceAge)personAge);
            }
            catch (Exception exception)
            {
                throw new SapiManagerException(exception.Message, exception);
            }
        }

        /// <summary>
        /// Speaks the given text provided.
        /// </summary>
        /// <param name="textToSpeak">Text to speak.</param>
        /// <exception cref="SapiManagerException">Thrown when 
        /// speaking text fails.</exception>
        public void Speak(string textToSpeak)
        {
            try
            {
                speechSynthesizer.SetOutputToDefaultAudioDevice();
                currentPrompt = speechSynthesizer.SpeakAsync(textToSpeak);
            }
            catch (Exception exception)
            {
                throw new SapiManagerException(exception.Message, exception);
            }
        }

        /// <summary>
        /// Speaks the text from the specified file.
        /// </summary>
        /// <param name="fileName">The file path/name to read text from. If string.Empty, the user will be prompted with a OpenDialog.</param>
        public void SpeakFile(string fileName)
        {
            SpeakFile(GetTextFromFile(fileName));
        }

        /// <summary>
        /// Speaks the text from a file. Prompts the user with a OpenDialog.
        /// </summary>
        public void SpeakFile()
        {
            SpeakFile(GetTextFromFile());
        }

        /// <summary>
        /// Speaks the given text provided.
        /// </summary>
        /// <param name="textToSpeak">Text in SSML format.</param>
        /// <exception cref="SapiManagerException">Thrown when 
        /// speaking text fails.</exception>
        public void SpeakSsml(string textToSpeak)
        {

            try
            {
                speechSynthesizer.SetOutputToDefaultAudioDevice();
                currentPrompt = speechSynthesizer.SpeakSsmlAsync(textToSpeak);
            }

            catch (Exception exception)
            {
                throw new SapiManagerException(exception.Message, exception);
            }

        }

        /// <summary>
        /// Speaks the given text provided and stores it in the form of .wav file.
        /// </summary>
        /// <param name="textToSpeak">Text to speak.</param>
        /// <param name="SsmlText">Keep it true if you are passing SSML text.</param>
        /// <exception cref="SapiManagerException">Thrown when 
        /// coverting text to wave file fails.</exception>
        public void ToWave(string textToSpeak, bool SsmlText)
        {
            ToWave(textToSpeak, string.Empty, SsmlText);
        }

        /// <summary>
        /// Speaks the given text provided and stores it in the form of .wav file.
        /// </summary>
        /// <param name="textToSpeak">Text to speak.</param>
        /// <param name="fileName">.Wav file name.</param>
        /// <param name="SsmlText">Keep it true if you are passing SSML text.</param>
        /// <exception cref="SapiManagerException">Thrown when 
        /// coverting text to wave file fails.</exception>
        public void ToWave(string textToSpeak, string fileName, bool SsmlText)
        {
            try
            {
                if (fileName == string.Empty)
                {
                    SaveFileDialog sfd = new SaveFileDialog();
                    sfd.Filter = string.Format("All files (*.*)|*.*|{0} files (*.{0})|*.{0}", WAV_EXTENSION);
                    sfd.Title = "Save to a wave file";
                    sfd.FilterIndex = 2;
                    sfd.RestoreDirectory = true;

                    if (sfd.ShowDialog() == DialogResult.OK && !string.IsNullOrEmpty(sfd.FileName))
                    {
                        fileName = sfd.FileName;
                    }
                }

                if (!string.IsNullOrEmpty(fileName))
                {
                    speechSynthesizer.SetOutputToWaveFile(fileName);
                    if (SsmlText == false)
                    {
                        speechSynthesizer.SpeakAsync(textToSpeak);
                    }
                    else
                    {
                        speechSynthesizer.SpeakSsmlAsync(textToSpeak);
                    }
                }
            }
            catch (Exception exception)
            {
                throw new SapiManagerException(exception.Message, exception);
            }
        }

        /// <summary>
        /// Speaks the given text provided and generates stream out of it.
        /// </summary>
        /// <param name="textToSpeak">Text to speak.</param>
        /// <param name="SsmlText">Keep it true if you are passing SSML text.</param>
        /// <returns>Stream</returns>
        /// <exception cref="SapiManagerException">Thrown when 
        /// converting text to stream fails.</exception>
        public System.IO.Stream ToStream(string textToSpeak, bool SsmlText)
        {

            try
            {

                System.IO.MemoryStream tempStream = new System.IO.MemoryStream();
                speechSynthesizer.SetOutputToWaveStream(tempStream);

                if (SsmlText == false)
                {
                    speechSynthesizer.Speak(textToSpeak);
                }
                else
                {
                    speechSynthesizer.SpeakSsml(textToSpeak);
                }

                speechSynthesizer.SetOutputToDefaultAudioDevice();

                return tempStream;

            }

            catch (Exception exception)
            {
                throw new SapiManagerException(exception.Message, exception);
            }

        }

        /// <summary>
        /// Pauses speaking.
        /// </summary>
        /// <exception cref="SapiManagerException">Thrown when 
        /// pausing speech synthesizer engine fails.</exception>
        public void PauseSpeaking()
        {

            try
            {
                speechSynthesizer.Pause();
            }

            catch (Exception exception)
            {
                throw new SapiManagerException(exception.Message, exception);
            }

        }

        /// <summary>
        /// Resumes speaking.
        /// </summary>
        /// <exception cref="SapiManagerException">Thrown when 
        /// resuming speech synthesizer engine fails.</exception>
        public void ResumeSpeaking()
        {

            try
            {
                speechSynthesizer.Resume();
            }

            catch (Exception exception)
            {
                throw new SapiManagerException(exception.Message, exception);
            }

        }

        /// <summary>
        /// Stops speaking.
        /// </summary>
        /// <exception cref="SapiManagerException">Thrown when 
        /// stopping speech synthesizer engine fails.</exception>
        public void StopSpeaking()
        {

            try
            {
                speechSynthesizer.SpeakAsyncCancel(currentPrompt);
            }
            catch (Exception exception)
            {
                throw new SapiManagerException(exception.Message, exception);
            }
        }

        /// <summary>
        /// Retrieves the text from the specified file. User will be prompted with an open dialog.
        /// </summary>
        /// <param name="fileName">The file path/name to retrieve text from. If string.empty, the user will be prompted with an OpenDialog.</param>
        /// <returns>The text of the file.</returns>
        public string GetTextFromFile(string fileName)
        {
            if (string.IsNullOrEmpty(fileName))
            {
                OpenFileDialog dlg = new OpenFileDialog();

                if (dlg.ShowDialog() == DialogResult.OK && !string.IsNullOrEmpty(dlg.FileName))
                {
                    string filePath = dlg.FileName;
                    StreamReader file = File.OpenText(filePath);

                    fileName = file.ReadToEnd();
                }
            }

            return fileName ?? string.Empty;
        }

        /// <summary>
        /// Retrieves the text from a file. User will be prompted with an OpenDialog.
        /// </summary>
        /// <returns>The text from the file.</returns>
        public string GetTextFromFile()
        {
            return GetTextFromFile(string.Empty);
        }

        #endregion

        #region Recognition related methods

        /// <summary>
        /// Gives the list of recognizers available on the machine.
        /// </summary>
        /// <returns>List of structure of recognizers.</returns>
        /// <exception cref="SapiManagerException">Thrown when 
        /// collecting information about installed recognizers fails.</exception>
        public static List<RecognizerInfo> GetInstalledRecognizers()
        {
            try
            {
                List<RecognizerInfo> installedRecognizers = new List<RecognizerInfo>();
                System.Collections.ObjectModel.ReadOnlyCollection<System.Speech.Recognition.RecognizerInfo> recognizers = SpeechRecognitionEngine.InstalledRecognizers();
                foreach (System.Speech.Recognition.RecognizerInfo recognizer in recognizers)
                {
                    RecognizerInfo recognizerInfo = new RecognizerInfo();
                    recognizerInfo.Description = recognizer.Description;
                    recognizerInfo.RecognizerId = recognizer.Id;
                    recognizerInfo.Name = recognizer.Name;
                    installedRecognizers.Add(recognizerInfo);
                }

                return installedRecognizers;

            }

            catch (Exception exception)
            {
                throw new SapiManagerException(exception.Message, exception);
            }

        }

        /// <summary>
        /// Initializes Dictation engine.
        /// </summary>
        /// <param name="recognizerId">Id of reconition engine, if null is provided then default will be used.</param>
        /// <returns>Returns true if succeeded.</returns>
        /// <exception cref="SapiManagerException">Thrown when 
        /// initializing Dictation engine fails.</exception>
        public bool InitializeDictationEngine(string recognizerId)
        {
            try
            {

                if (!string.IsNullOrEmpty(recognizerId))
                {
                    dictationRecognizerEngine = new SpeechRecognitionEngine(recognizerId);
                }
                else
                {
                    dictationRecognizerEngine = new SpeechRecognitionEngine(CultureInfo.CurrentCulture);
                }

                dictationRecognizerEngine.SetInputToDefaultAudioDevice();
                dictationGrammar = new DictationGrammar();
                dictationRecognizerEngine.UnloadAllGrammars();
                dictationRecognizerEngine.LoadGrammar(dictationGrammar);
                dictationRecognizerEngine.SpeechRecognized += new System.EventHandler<SpeechRecognizedEventArgs>(DictationRecognizerEngine_SpeechRecognized);
                dictationRecognizerEngine.RecognizeCompleted += new EventHandler<RecognizeCompletedEventArgs>(DictationRecognizerEngine_RecognizeCompleted);

                return true;

            }

            catch (Exception exception)
            {
                throw new SapiManagerException(exception.Message, exception);
            }

        }

        /// <summary>
        /// Initializes Dictation engine.
        /// </summary>
        /// <param name="recognizerId">Id of reconition engine, if null is provided then default will be used.</param>
        /// <param name="streamToRecognize">Stream of data.</param>
        /// <returns>Returns true if succeeded.</returns>
        /// <exception cref="SapiManagerException">Thrown when 
        /// initializing Dictation engine fails.</exception>
        public bool InitializeDictationEngine(string recognizerId, System.IO.Stream streamToRecognize)
        {
            try
            {
                if (!string.IsNullOrEmpty(recognizerId))
                {
                    dictationRecognizerEngine = new SpeechRecognitionEngine(recognizerId);
                }
                else
                {
                    dictationRecognizerEngine = new SpeechRecognitionEngine(CultureInfo.CurrentCulture);
                }
                dictationRecognizerEngine.SetInputToWaveStream(streamToRecognize);
                dictationGrammar = new DictationGrammar();
                dictationRecognizerEngine.UnloadAllGrammars();
                dictationRecognizerEngine.LoadGrammar(dictationGrammar);
                dictationRecognizerEngine.SpeechRecognized += new System.EventHandler<SpeechRecognizedEventArgs>(DictationRecognizerEngine_SpeechRecognized);
                dictationRecognizerEngine.RecognizeCompleted += new EventHandler<RecognizeCompletedEventArgs>(DictationRecognizerEngine_RecognizeCompleted);
                return true;
            }
            catch (Exception exception)
            {
                throw new SapiManagerException(exception.Message, exception);
            }
        }

        /// <summary>
        /// Initializes Dictation engine.
        /// </summary>
        /// <param name="recognizerId">Id of reconition engine, if null is provided then default will be used.</param>
        /// <param name="filePath">.Wav file for recognize</param>
        /// <returns>Returns true if succeeded.</returns>
        /// <exception cref="SapiManagerException">Thrown when 
        /// initializing Dictation engine fails.</exception>
        public bool InitializeDictationEngine(string recognizerId, string filePath)
        {

            try
            {
                if (!string.IsNullOrEmpty(recognizerId))
                {
                    dictationRecognizerEngine = new SpeechRecognitionEngine(recognizerId);
                }
                else
                {
                    dictationRecognizerEngine = new SpeechRecognitionEngine(CultureInfo.CurrentCulture);
                }

                dictationRecognizerEngine.SetInputToWaveFile(filePath);
                dictationGrammar = new DictationGrammar();
                dictationRecognizerEngine.UnloadAllGrammars();
                dictationRecognizerEngine.LoadGrammar(dictationGrammar);
                dictationRecognizerEngine.SpeechRecognized += new System.EventHandler<SpeechRecognizedEventArgs>(DictationRecognizerEngine_SpeechRecognized);
                dictationRecognizerEngine.RecognizeCompleted += new EventHandler<RecognizeCompletedEventArgs>(DictationRecognizerEngine_RecognizeCompleted);

                return true;
            }

            catch (Exception exception)
            {
                throw new SapiManagerException(exception.Message, exception);
            }

        }

        /// <summary>
        /// Initializes Speech Recognition engine.
        /// </summary>
        /// <param name="recognizerId">Id of reconition engine, if null is provided then default will be used.</param>
        /// <param name="words">Array of words for grammar.</param>
        /// <returns>Returns true if succeeded.</returns>
        /// <exception cref="SapiManagerException">Thrown when 
        /// initializing Speech Recognition engine fails.</exception>
        public bool InitializeSpeechRecognitionEngine(string recognizerId, string[] words)
        {

            try
            {

                if (!string.IsNullOrEmpty(recognizerId))
                {
                    recognizerEngine = new SpeechRecognitionEngine(recognizerId);
                }
                else
                {
                    recognizerEngine = new SpeechRecognitionEngine(CultureInfo.CurrentCulture);
                }

                recognizerEngine.SetInputToDefaultAudioDevice();
                customGrammar = CreateCustomGrammar(words);
                recognizerEngine.UnloadAllGrammars();

                if (customGrammar != null)
                {
                    recognizerEngine.LoadGrammar(customGrammar);
                }

                recognizerEngine.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(RecognizerEngineSpeechRecognized);
                recognizerEngine.RecognizeCompleted += new EventHandler<RecognizeCompletedEventArgs>(RecognizerEngineRecognizeCompleted);
                return true;

            }

            catch (Exception exception)
            {
                throw new SapiManagerException(exception.Message, exception);
            }

        }

        /// <summary>
        /// Initializes Speech Recognition engine.
        /// </summary>
        /// <param name="recognizerId">Id of reconition engine, if null is provided then default will be used.</param>
        /// <param name="words">Array of words for grammar.</param>
        /// <param name="stream">Stream of data to recognize.</param>
        /// <returns>Returns true if succeeded.</returns>
        /// <exception cref="SapiManagerException">Thrown when 
        /// initializing Speech Recognition engine fails.</exception>
        public bool InitializeSpeechRecognitionEngine(string recognizerId, string[] words, System.IO.Stream stream)
        {

            try
            {
                if (!string.IsNullOrEmpty(recognizerId))
                {
                    recognizerEngine = new SpeechRecognitionEngine(recognizerId);
                }
                else
                {
                    recognizerEngine = new SpeechRecognitionEngine(CultureInfo.CurrentCulture);
                }

                recognizerEngine.SetInputToAudioStream(stream, null);
                customGrammar = CreateCustomGrammar(words);
                recognizerEngine.UnloadAllGrammars();

                if (customGrammar != null)
                {
                    recognizerEngine.LoadGrammar(customGrammar);
                }

                recognizerEngine.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(RecognizerEngineSpeechRecognized);
                recognizerEngine.RecognizeCompleted += new EventHandler<RecognizeCompletedEventArgs>(RecognizerEngineRecognizeCompleted);

                return true;

            }

            catch (Exception exception)
            {
                throw new SapiManagerException(exception.Message, exception);
            }

        }

        /// <summary>
        /// Initializes Speech Recognition engine.
        /// </summary>
        /// <param name="recognizerId">Id of reconition engine, if null is provided then default will be used.</param>
        /// <param name="words">Array of words for grammar.</param>
        /// <param name="filePath">.Wav file for recognize</param>
        /// <returns>Returns true if succeeded.</returns>
        /// <exception cref="SapiManagerException">Thrown when 
        /// initializing Speech Recognition engine fails.</exception>
        public bool InitializeSpeechRecognitionEngine(string recognizerId, string[] words, string filePath)
        {

            try
            {

                if (!string.IsNullOrEmpty(recognizerId))
                {
                    recognizerEngine = new SpeechRecognitionEngine(recognizerId);
                }
                else
                {
                    recognizerEngine = new SpeechRecognitionEngine(CultureInfo.CurrentCulture);
                }

                recognizerEngine.SetInputToWaveFile(filePath);
                customGrammar = CreateCustomGrammar(words);
                recognizerEngine.UnloadAllGrammars();

                if (customGrammar != null)
                {
                    recognizerEngine.LoadGrammar(customGrammar);
                }

                recognizerEngine.SpeechRecognized +=new EventHandler<SpeechRecognizedEventArgs>(RecognizerEngineSpeechRecognized);
                recognizerEngine.RecognizeCompleted += new EventHandler<RecognizeCompletedEventArgs>(RecognizerEngineRecognizeCompleted);

                return true;

            }

            catch (Exception exception)
            {
                throw new SapiManagerException(exception.Message, exception);
            }

        }

        private void RecognizerEngineRecognizeCompleted(object sender, RecognizeCompletedEventArgs e)
        {

            try
            {
                recognizerEngine.SetInputToDefaultAudioDevice();
            }
            catch (Exception exception)
            {
                throw new SapiManagerException(exception.Message, exception);
            }

        }

        private void RecognizerEngineSpeechRecognized(object sender, SpeechRecognizedEventArgs e)
        {
            SpeechRecognized(e.Result.Text);
        }

        private void DictationRecognizerEngine_RecognizeCompleted(object sender, RecognizeCompletedEventArgs e)
        {

            try
            {
                dictationRecognizerEngine.SetInputToDefaultAudioDevice();
            }
            catch (Exception exception)
            {
                throw new SapiManagerException(exception.Message, exception);
            }

        }

        private void DictationRecognizerEngine_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
        {
            SpeechRecognized(e.Result.Text);
        }

        /// <summary>
        /// Starts Speech Recognition engine.
        /// </summary>
        /// <exception cref="SapiManagerException">Thrown when 
        /// starting Speech Recognition engine fails.</exception>
        public void StartSpeechRecognitionEngine()
        {

            try
            {
                recognizerEngine.RecognizeAsync(RecognizeMode.Multiple);
            }

            catch (Exception exception)
            {
                throw new SapiManagerException(exception.Message, exception);
            }

        }

        /// <summary>
        /// Starts Dictation engine.
        /// </summary>
        /// <exception cref="SapiManagerException">Thrown when 
        /// starting Dictation engine fails.</exception>
        public void StartDictationEngine()
        {

            try
            {
                dictationRecognizerEngine.RecognizeAsync(RecognizeMode.Multiple);
            }

            catch (Exception exception)
            {
                throw new SapiManagerException(exception.Message, exception);
            }

        }

        /// <summary>
        /// Stops the Speech Recognition engine.
        /// </summary>
        /// <exception cref="SapiManagerException">Thrown when 
        /// stopping Speech Recognition engine fails.</exception>
        public void StopSpeechRecognitionEngine()
        {

            try
            {
                if (recognizerEngine != null)
                {
                    recognizerEngine.RecognizeAsyncCancel();
                }
            }

            catch (Exception exception)
            {
                throw new SapiManagerException(exception.Message, exception);
            }

        }

        /// <summary>
        /// Stops the Dictation engine.
        /// </summary>
        /// <exception cref="SapiManagerException">Thrown when 
        /// stopping Dictation engine fails.</exception>
        public void StopDictationEngine()
        {

            try
            {
                if (dictationRecognizerEngine != null)
                {
                    dictationRecognizerEngine.RecognizeAsyncCancel();
                }
            }

            catch (Exception exception)
            {
                throw new SapiManagerException(exception.Message, exception);
            }

        }

        /// <summary>
        /// Creates grammar for given words.
        /// </summary>
        /// <param name="words">Array of words for grammar.</param>
        /// <returns>Custom grammar for given words.</returns>
        private Grammar CreateCustomGrammar(string[] words)
        {

            try
            {
                GrammarBuilder grammarBuilder = new GrammarBuilder();
                grammarBuilder.Append(new Choices(words));
                return new Grammar(grammarBuilder);
            }

            catch (Exception exception)
            {
                throw new SapiManagerException(exception.Message, exception);
            }

        }

        #endregion

        #endregion

    }

}